package top.techqi.usbd.desc

import top.techqi.core.util.FmtUtil

class IntfDesc(
    val bInterfaceNumber: Byte,
    val bAlternateSetting: Byte,
    val bNumEndpoints: Byte,
    val bInterfaceClass: Byte,
    val bInterfaceSubClass: Byte,
    val bInterfaceProtocol: Byte,
    val iInterface: Byte,

    val interfaceName: String?,
) : AbstractDesc(LENGTH, TYPE) {
    var specs = arrayOf<CSDesc>()
        internal set

    constructor(
        bytes: ByteArray,
        interfaceName: String?,
    ) : this(
        bytes[2],
        bytes[3],
        bytes[4],
        bytes[5],
        bytes[6],
        bytes[7],
        bytes[8],

        interfaceName,
    ) {
        require(bytes[0] == LENGTH && bytes[1] == TYPE) {
            "Invalid length or type: ${bytes[0]}, ${bytes[1]}"
        }
    }

    override fun toString(): String {
        return """
        IntfDesc(
            bInterfaceNumber    = %1${'$'}s,
            bAlternateSetting   = %2${'$'}s,
            bNumEndpoints       = %3${'$'}s,
            bInterfaceClass     = %4${'$'}s,
            bInterfaceSubClass  = %5${'$'}s,
            bInterfaceProtocol  = %6${'$'}s,
            iInterface          = %7${'$'}s,%8${'$'}s
        )
        """.trimIndent().format(
            bInterfaceNumber,
            bAlternateSetting,
            bNumEndpoints,
            bInterfaceClass,
            bInterfaceSubClass,
            bInterfaceProtocol,
            "%1$-2d(%2\$s)".format(iInterface, interfaceName),
            specs.joinToString(",\n", prefix = "\n") {
                it.toString()
            }.replace("\n", "\n    ")
        )
    }

    class CSDesc(
        bLength: Byte,
        val bDescriptorSubtype: Byte,
        vararg val bytes: Byte
    ) : AbstractDesc(bLength, TYPE) {
        constructor(bytes: ByteArray) : this(
            bytes[0],
            bytes[2],
            *bytes.sliceArray(3..<bytes[0])
        ) {
            require(bytes[1] == TYPE) {
                "Invalid type: ${bytes[1]}"
            }
        }

        override fun toString(): String {
            return """
            CSDesc(
                bLength           = %1${'$'}s,
                bDescriptorSubtype= %2${'$'}s,
                bytes             = %3${'$'}s
            )
            """.trimIndent().format(
                bLength,
                bDescriptorSubtype,
                bytes.joinToString(",") { FmtUtil.toHexString(it, "") }
            )
        }

        companion object {
            const val TYPE: Byte = 0x24
        }
    }

    companion object {
        const val TYPE: Byte = 0x04
        const val LENGTH: Byte = 9
    }
}
